package com.hspedu.qqserver.service;

import com.hspedu.qqcommon.Message;
import com.hspedu.qqcommon.MessageType;
import com.hspedu.qqcommon.User;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author Stringzhua
 * @Date 2024/4/11 11:15
 * description:这是服务器,在监听9999端口,等待客户端连接,并保持通讯
 */
public class QQServer {
    private ServerSocket ss = null;
    //创建一个集合,存放多个用户,如果是这些用户登录,就认为登录是合法的
    //这里我们也可以使用ConcurrentHashMap,可以处理并发集合,没有线程安全问题
    //HaahMap没有处理线程安全问题,因此在多线程情况下是不安全的
    //ConcurrentHashMap 处理的线程安全,即线程同步处理,在多线程情况下是不安全
    private static ConcurrentHashMap<String, User> validUsers = new ConcurrentHashMap<>();
    //TODO:离线发送文件和消息
//    private static ConcurrentHashMap<String, ArrayList<Message>> offLineDb = new ConcurrentHashMap<>();
//    private static HashMap<String, User> validUsers = new HashMap<>();

    static {
        //在静态代码块,初始化validUsers
//        offLineDb.remove("100");
        validUsers.put("100", new User("100", "123456"));
        validUsers.put("200", new User("200", "123456"));
        validUsers.put("300", new User("300", "123456"));
        validUsers.put("至尊宝", new User("至尊宝", "123456"));
        validUsers.put("紫霞仙子", new User("紫霞仙子", "123456"));
        validUsers.put("菩提老祖", new User("菩提老祖", "123456"));
    }

    //验证用户是否有效的方法
    private boolean checkUser(String userId, String password) {
        User user = validUsers.get(userId);
        //过关斩将的验证方式
        if (user == null) {
            //说明userId没有存放validUsers 的key中
            return false;
        }
        if (!user.getPassword().equals(password)) {//userId正确但密码错误
            return false;
        }
        return true;
    }

    //构造器
    public QQServer() {
        try {
            //注意,端口可以写在配置文件中
            System.out.println("服务端在9999端口监听...");
            //启动推送新闻的线程
            new Thread(new SendNewsToAllServices()).start();
            ss = new ServerSocket(9999);

            while (true) {//当和某个客户端建立连接后,会继续监听,所以这里用while循环
                Socket socket = ss.accept();//如果没有客户端连接,就会阻塞在这
                //得到socket关联的对象输入流
                ObjectInputStream ois =
                        new ObjectInputStream(socket.getInputStream());
                //得到socket对象关联的对象输出流
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                User u = (User) ois.readObject();//读取该客户端发送的User对象
                //创建一个Message对象,准备回复客户端
                Message message = new Message();
                //验证用户
//                if (checkUser(u.getUserId(), u.getPassword())) {
//                    //登录成功
//                    message.setMessageType(MessageType.MESSAGE_LOGIN_SUCCESS);
//                    //将Message对象回复客户端
//                    oos.writeObject(message);
//                    //创建一个线程,和客户端保持通信,该线程持有socket对象
//                    ServerConnectClientThread serverConnectClientThread =
//                            new ServerConnectClientThread(socket, u.getUserId());
//                    //启动线程
//                    serverConnectClientThread.start();
//                    //把该线程对象,放入到一个集合中,进行管理
//                    ManageClientThreads.addClientThread(u.getUserId(), serverConnectClientThread);
//                } else {
//                    //登陆失败
//                    System.out.println("用户 id=" + u.getUserId() + "  pwd=" + u.getPassword() + "  登陆失败");
//                    message.setMessageType(MessageType.MESSAGE_LOGIN_FAIL);
//                    oos.writeObject(message);
//                    //关闭socket
//                    socket.close();
//                }
                //TODO:用户登录成功后调用方法发送离线消息
                if (checkUser(u.getUserId(), u.getPassword())) {//验证通过
                    message.setMessageType(MessageType.MESSAGE_LOGIN_SUCCESS);
                    //将message对象回复
                    oos.writeObject(message);
                    //创建一个线程，和客户端保持通讯，该线程持有socket对象
                    ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, u.getUserId());
                    serverConnectClientThread.start();
                    //把该线程对象放入到集合中进行管理
                    ManageClientThreads.addClientThread(u.getUserId(), serverConnectClientThread);
                    ConcurrentHashMap<String, ArrayList> offlineMap = OffLineMessageService.getOfflineMap();
                    //发送离线消息
                    OffLineMessageService.sendOfflineMessage(u.getUserId(), offlineMap);
                    OffLineMessageService.deleteOfflineMessage(u.getUserId());

                } else {
                    System.out.println("用户 id=" + u.getUserId() + " pwd=" + u.getPassword() + " 验证失败");
                    message.setMessageType(MessageType.MESSAGE_LOGIN_FAIL);
                    oos.writeObject(message);
                    //关闭socket
                    socket.close();

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果服务端退出了while循环,说明服务器端不再监听,因此关闭ServerSocket
            try {
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
